#pragma once 

#include <iostream>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <time.h>
#include <stdarg.h>
#include <fstream>
#include <pthread.h>
#include "LockGuard.hpp"


#define SCREEN 1
#define FILE_TYPE 2

pthread_mutex_t gmutex = PTHREAD_MUTEX_INITIALIZER;
const std::string glogfile = "./log.txt";

enum
{
    DEBUG = 1,
    INFO,
    WARNING,
    ERROR,
    FATAL
};

class LogMessage
{
public:
    std::string _level;
    pid_t _pid;
    std::string _filename;
    int _filenumber;
    std::string _current_time;
    std::string _message_info;
};

std::string LevelToString(int level)
{
    switch (level)
    {
    case DEBUG:
        return "DEBUG";
    case INFO:
        return "INFO";
    case WARNING:
        return "WARNING";
    case ERROR:
        return "ERROR";
    case FATAL:
        return "FATAL";
    default:
        return "UNKNOW";
    }
}

std::string GetTime()
{
    time_t t = time(nullptr);

    struct tm* cur_time= localtime(&t);
    

    char buff[128];

    snprintf(buff,sizeof(buff) , "%d-%d-%d %02d:%02d:%02d",\
                                cur_time->tm_year+1900,\
                                cur_time->tm_mon+1,\
                                cur_time->tm_mday,\
                                cur_time->tm_hour,\
                                cur_time->tm_min,\
                                cur_time->tm_sec);
    return buff;
}

//log.logMessage(__FILENAME__ , __LINE__,"this is %d message",x);
class Log
{
public:

    Log(const std::string& filename = glogfile)
    :_type(SCREEN)
    ,_log_file(filename)
    {}
    void FlushLogScreen(const LogMessage& lg)
    {
        printf("[%s][%d][%s][%d][%s] %s",lg._level.c_str(),\
                                        lg._pid,\
                                        lg._filename.c_str(),\
                                        lg._filenumber,\
                                        lg._current_time.c_str(),\
                                        lg._message_info.c_str());
    }

    void FlushLogFile(const LogMessage& lg)
    {
        std::ofstream out(_log_file,std::ostream::app);
        if(!out.is_open())  
            return ;
        char buff[1024];
        snprintf(buff,sizeof(buff),"[%s][%d][%s][%d][%s] %s",lg._level.c_str(),\
                                        lg._pid,\
                                        lg._filename.c_str(),\
                                        lg._filenumber,\
                                        lg._current_time.c_str(),\
                                        lg._message_info.c_str());
        out.write(buff,strlen(buff));
        out.close();
    }

    void Flush(const LogMessage& lg)
    {
        LockGuard lock(&gmutex);
        switch (_type)
        {
        case SCREEN:
            FlushLogScreen(lg);
            break;
        case FILE_TYPE:
            FlushLogFile(lg);
            break;
        }
    }

    void Enable(int type)
    {
        _type = type;
    }

    void logMessage(std::string filename,int filenumber,int level,const char* info,...)
    {
        LogMessage lg;

        lg._level = LevelToString(level);
        lg._pid = getpid();
        lg._filename = filename;
        lg._filenumber = filenumber;
        lg._current_time = GetTime();
        
        va_list ap;
        va_start(ap,info);
        char log_info[1024];
        vsnprintf(log_info,sizeof(log_info),info,ap);
        va_end(ap);

        lg._message_info = log_info;

        //打印出来
        Flush(lg);
    }

    ~Log()
    {}

private:
    int _type;
    std::string _log_file;
};

Log lg;

#define LOG(Level,Format,...)do{lg.logMessage(__FILE__,__LINE__,Level,Format,##__VA_ARGS__); }while(0)
#define EnableScreen()do{lg.Enable(SCREEN);}while(0)
#define EnableFILE()do{lg.Enable(FILE_TYPE);}while(0)

